// yemu.h
#ifndef YEMU
#define YEMU

#include <stdint.h>

// RISC-V General Purpose Register Index Macros (ABI names and descriptions)
#define zero 0   // x0: Hard-wired zero, always 0
#define ra   1   // x1: Return address
#define sp   2   // x2: Stack pointer
#define gp   3   // x3: Global pointer
#define tp   4   // x4: Thread pointer

#define t0   5   // x5: Temporary register 0
#define t1   6   // x6: Temporary register 1
#define t2   7   // x7: Temporary register 2

#define s0   8   // x8: Saved register 0 / Frame pointer (s0/fp)
#define fp   8   // x8: Frame pointer (alias of s0)
#define s1   9   // x9: Saved register 1

#define a0   10  // x10: Function argument 0 / return value 0
#define a1   11  // x11: Function argument 1 / return value 1
#define a2   12  // x12: Function argument 2
#define a3   13  // x13: Function argument 3
#define a4   14  // x14: Function argument 4
#define a5   15  // x15: Function argument 5
#define a6   16  // x16: Function argument 6
#define a7   17  // x17: Function argument 7

#define s2   18  // x18: Saved register 2
#define s3   19  // x19: Saved register 3
#define s4   20  // x20: Saved register 4
#define s5   21  // x21: Saved register 5
#define s6   22  // x22: Saved register 6
#define s7   23  // x23: Saved register 7
#define s8   24  // x24: Saved register 8
#define s9   25  // x25: Saved register 9
#define s10  26  // x26: Saved register 10
#define s11  27  // x27: Saved register 11

#define t3   28  // x28: Temporary register 3
#define t4   29  // x29: Temporary register 4
#define t5   30  // x30: Temporary register 5
#define t6   31  // x31: Temporary register 6

#define COLOR_RED       "\x1b[31m"
#define COLOR_GREEN     "\x1b[32m"
#define COLOR_YELLOW    "\x1b[33m"
#define COLOR_BLUE      "\x1b[34m"
#define COLOR_MAGENTA   "\x1b[35m"
#define COLOR_CYAN      "\x1b[36m"
#define COLOR_RESET     "\x1b[0m"

#define MEM_SIZE        (4UL * 1024 * 1024 * 1024) // 4GB
#define MEM_OFFSET      (0x80000000)
#define UART_TX_ADDR    (0x10000000)
#define UART_RX_ADDR    (0x10000004)
#define CLOCK_ADDR      (0x12345678)

enum INSTKIND {
    ILL, // illegal
    LUI, AUIPC,      
    SLT, SLTI, SLTU, SLTIU,
    OR, AND, XOR, ORI, ANDI, XORI, 
    ADD, ADDI, ADDW, ADDIW, SUB, SUBW,
    BEQ, BNE, BLT, BGE, BLTU, BGEU, JAL, JALR, 
    LB, LH, LW, LD, LBU, LHU, LWU, SB, SH, SW, SD, 
    SLL, SRL, SRA, SLLI, SRLI, SRAI, SLLW, SRLW, SRAW, SLLIW, SRLIW, SRAIW,
    InstCnt
};

struct INSTINFO {
    uint32_t Inst;
    enum INSTKIND InstKind;
    uint8_t rd;
    uint8_t rs1;
    uint8_t rs2;
    uint64_t imm;
};

struct ARCHINFO {
    uint64_t PC;
    uint64_t Regs[32];
    uint64_t Mcycle;
    unsigned char* Mem;
};

void Logo();
void Reset(struct ARCHINFO* ArchInfo);
void Halt(struct ARCHINFO* ArchInfo);

uint32_t InstFetch(struct ARCHINFO ArchInfo);
struct INSTINFO InstDecode(uint32_t Inst);
struct ARCHINFO Execute(struct ARCHINFO ArchInfo, struct INSTINFO InstInfo);

int64_t SignExt(uint64_t data, int sign_bit);
uint8_t MemRead(struct ARCHINFO ArchInfo, uint64_t raddr);
void MemWrite(struct ARCHINFO ArchInfo, uint64_t waddr, uint8_t wdata);

#endif
